//
//  LxGridViewFlowLayout.m
//  LxGridView
//

#import "LxGridView.h"
#import "THFilterModel.h"
#import "UIView+Layout.h"

@implementation LxGridView


- (void)setEditing:(BOOL)editing {
    _editing = editing;
    for (int i = 0; i < self.visibleCells.count; i ++) {
        UICollectionViewCell *cell = self.visibleCells[i];
        if ([cell isKindOfClass:[THEditImgCell class]]) {
            THEditImgCell *gridViewCell = (THEditImgCell *)cell;
            gridViewCell.editing = editing;
        }
//        NSCAssert([cell isKindOfClass:[THEditImgCell class]] || cell == nil, @"LxGridView: Must use THEditImgCell as your collectionViewCell class!");
    }
}


@end


@implementation THImgCollectionViewCell

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self configView];
    }
    return self;
}

- (void)configView {
    UIButton *addBtn = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, self.contentView.tz_width - 20, self.contentView.tz_width - 20)];
    [addBtn setImage:[UIImage imageNamed:@"addpic"] forState:UIControlStateNormal];
    [addBtn addTarget:self action:@selector(addBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.contentView addSubview:addBtn];
    self.addBtn = addBtn;
}

- (void)addBtnClick:(UIButton *)sender {
    if (self.addBtnClickBlock) {
        self.addBtnClickBlock();
    }
}

@end


@implementation THEditImgCell

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self configView];
    }
    return self;
}

- (void)configView {
    CGFloat imgWidth = self.contentView.tz_width - 20;
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, imgWidth, imgWidth)];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.clipsToBounds = YES;
    [self.contentView addSubview:imageView];
    self.imageView = imageView;

    UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxX(imageView.frame), self.contentView.tz_width, 20)];
    lable.textAlignment = NSTextAlignmentCenter;
    lable.font = [UIFont systemFontOfSize:15];
    [self.contentView addSubview:lable];
    self.lable = lable;

    UIButton *deleBtn = [[UIButton alloc] initWithFrame:CGRectMake(imgWidth, 0, 20, 20)];
    [deleBtn setImage:[UIImage imageNamed:@"Delete Icon"] forState:UIControlStateNormal];
    [deleBtn addTarget:self action:@selector(deleBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.contentView addSubview:deleBtn];
    self.deleBtn = deleBtn;
}

- (void)setModel:(THTextureModel *)model {
    _model = model;
    self.imageView.image = [UIImage imageNamed:model.img];
    self.lable.text = model.name;
}

- (void)setEditing:(BOOL)editing {
    _editing = editing;
    _deleBtn.hidden = !editing;
}


- (void)deleBtnClick:(UIButton *)sender {
    if (self.deleBtnClickBlock) {
        self.deleBtnClickBlock(self);
    }
}


- (UIView *)snapshotView {
    UIView *snapshotView = [[UIView alloc] init];

    UIView *cellSnapshotView = nil;

    if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) {
        cellSnapshotView = [self snapshotViewAfterScreenUpdates:NO];
    } else {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0);
        [self.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *cellSnapshotImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        cellSnapshotView = [[UIImageView alloc] initWithImage:cellSnapshotImage];
    }

    snapshotView.frame = CGRectMake(0, 0, cellSnapshotView.frame.size.width, cellSnapshotView.frame.size.height);
    cellSnapshotView.frame = CGRectMake(0, 0, cellSnapshotView.frame.size.width,cellSnapshotView.frame.size.height);

    [snapshotView addSubview:cellSnapshotView];

    return snapshotView;
}

@end



static CGFloat const PRESS_TO_MOVE_MIN_DURATION = 0.1;
static CGFloat const MIN_PRESS_TO_BEGIN_EDITING_DURATION = 0.6;

CG_INLINE CGPoint CGPointOffset(CGPoint point, CGFloat dx, CGFloat dy) {
    return CGPointMake(point.x + dx, point.y + dy);
}

@interface LxGridViewFlowLayout () <UIGestureRecognizerDelegate>

@property (nonatomic, readonly) id<LxGridViewDataSource> dataSource;
@property (nonatomic, readonly) id<LxGridViewDelegateFlowLayout> delegate;
@property (nonatomic, assign) BOOL editing;
@property (nonatomic, strong) NSMutableArray *layoutAttributes;

@end

@implementation LxGridViewFlowLayout {
    UILongPressGestureRecognizer *_longPressGestureRecognizer;
    UIPanGestureRecognizer *_panGestureRecognizer;
    NSIndexPath *_movingItemIndexPath;
    UIView *_beingMovedPromptView;
    CGPoint _sourceItemCollectionViewCellCenter;

    CADisplayLink *_displayLink;
    CFTimeInterval _remainSecondsToBeginEditing;

    CGFloat _sumCellWidth;
    NSMutableArray *_attributeAttay;
}

#pragma mark - setup

- (void)dealloc {
    [_displayLink invalidate];

    [self removeGestureRecognizers];
    [self removeObserver:self forKeyPath:@stringify(collectionView)];
}

- (instancetype)init {
    if (self = [super init]) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    if (self = [super initWithCoder:coder]) {
        [self setup];
    }
    return self;
}

- (void)setup {
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    [self addObserver:self forKeyPath:@stringify(collectionView) options:NSKeyValueObservingOptionNew context:nil];
}

- (void)addGestureRecognizers {
    self.collectionView.userInteractionEnabled = YES;

    _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognizerTriggerd:)];
    _longPressGestureRecognizer.cancelsTouchesInView = NO;
    _longPressGestureRecognizer.minimumPressDuration = PRESS_TO_MOVE_MIN_DURATION;
    _longPressGestureRecognizer.delegate = self;

    for (UIGestureRecognizer *gestureRecognizer in self.collectionView.gestureRecognizers) {
        if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
            [gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer];
        }
    }

    [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];

    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizerTriggerd:)];
    _panGestureRecognizer.delegate = self;
    [self.collectionView addGestureRecognizer:_panGestureRecognizer];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
}

- (void)removeGestureRecognizers {
    if (_longPressGestureRecognizer) {
        if (_longPressGestureRecognizer.view) {
            [_longPressGestureRecognizer.view removeGestureRecognizer:_longPressGestureRecognizer];
        }
        _longPressGestureRecognizer = nil;
    }

    if (_panGestureRecognizer) {
        if (_panGestureRecognizer.view) {
            [_panGestureRecognizer.view removeGestureRecognizer:_panGestureRecognizer];
        }
        _panGestureRecognizer = nil;
    }

    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
}

#pragma mark - getter and setter implementation

- (id<LxGridViewDataSource>)dataSource {
    return (id<LxGridViewDataSource>)self.collectionView.dataSource;
}

- (id<LxGridViewDelegateFlowLayout>)delegate {
    return (id<LxGridViewDelegateFlowLayout>)self.collectionView.delegate;
}

- (void)setEditing:(BOOL)editing {
    NSCAssert([self.collectionView isKindOfClass:[LxGridView class]] || self.collectionView == nil, @"LxGridViewFlowLayout: Must use LxGridView as your collectionView class!");
    LxGridView *gridView = (LxGridView *)self.collectionView;
    gridView.editing = editing;
}

- (BOOL)editing {
    NSCAssert([self.collectionView isKindOfClass:[LxGridView class]] || self.collectionView == nil, @"LxGridViewFlowLayout: Must use LxGridView as your collectionView class!");
    LxGridView *gridView = (LxGridView *)self.collectionView;
    return gridView.editing;
}

#pragma mark - override UICollectionViewLayout methods

- (void)prepareLayout {
    _attributeAttay = [NSMutableArray array];
    [super prepareLayout];
    CGSize size = self.itemSize;
    CGFloat interitem = self.minimumInteritemSpacing;
    NSInteger item = 0;
    NSInteger section = 0;

    if ([self.dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
        section = [self.dataSource numberOfSectionsInCollectionView:self.collectionView];
    }
    if ([self.dataSource respondsToSelector:@selector(collectionView:numberOfItemsInSection:)]) {
        item = [self.dataSource collectionView:self.collectionView numberOfItemsInSection:section];
    }

    CGFloat cellWidth = size.width * item + (item - 1) * interitem;

    CGFloat nowWidth = (self.collectionView.frame.size.width - cellWidth) / 2;
    for (int i = 0; i < item; i++) {
        //设置每个item的位置等相关属性
        NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
        //创建一个布局属性类，通过indexPath来创建
        UICollectionViewLayoutAttributes * attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        //设置item的位置
        if (cellWidth < self.collectionView.tz_width) {
            attris.frame = CGRectMake(nowWidth + i * interitem, 0, size.width, size.height);
        } else {
            attris = [self layoutAttributesForItemAtIndexPath:index];
        }
        nowWidth += size.width;
        NSLog(@"%@", NSStringFromCGRect(attris.frame));
        [_attributeAttay addObject:attris];
    }

}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    for (UICollectionViewLayoutAttributes * layoutAttributes in _attributeAttay) {
        if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
            layoutAttributes.hidden = [layoutAttributes.indexPath isEqual:_movingItemIndexPath];
        }
    }
    return _attributeAttay;
}


- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
    if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
        layoutAttributes.hidden = [layoutAttributes.indexPath isEqual:_movingItemIndexPath];
    }
    NSLog(@"layoutAttributes == %@", NSStringFromCGRect(layoutAttributes.frame));
    return layoutAttributes;
}

#pragma mark - gesture

- (void)setPanGestureRecognizerEnable:(BOOL)panGestureRecognizerEnable {
    _panGestureRecognizer.enabled = panGestureRecognizerEnable;
}

- (BOOL)panGestureRecognizerEnable {
    return _panGestureRecognizer.enabled;
}

- (void)longPressGestureRecognizerTriggerd:(UILongPressGestureRecognizer *)longPress {
    switch (longPress.state) {
        case UIGestureRecognizerStatePossible:
            break;
        case UIGestureRecognizerStateBegan: {
            if (_displayLink == nil) {
                _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTriggered:)];
                _displayLink.frameInterval = 6;
                [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

                _remainSecondsToBeginEditing = MIN_PRESS_TO_BEGIN_EDITING_DURATION;
            }

            if (self.editing == NO) {
                return;
            }

            _movingItemIndexPath = [self.collectionView indexPathForItemAtPoint:[longPress locationInView:self.collectionView]];

            if ([self.dataSource respondsToSelector:@selector(collectionView:canMoveItemAtIndexPath:)] && [self.dataSource collectionView:self.collectionView canMoveItemAtIndexPath:_movingItemIndexPath] == NO) {
                _movingItemIndexPath = nil;
                return;
            }

            if ([self.delegate respondsToSelector:@selector(collectionView:layout:willBeginDraggingItemAtIndexPath:)]) {
                [self.delegate collectionView:self.collectionView layout:self willBeginDraggingItemAtIndexPath:_movingItemIndexPath];
            }

            UICollectionViewCell *sourceCollectionViewCell = [self.collectionView cellForItemAtIndexPath:_movingItemIndexPath];
            NSCAssert([sourceCollectionViewCell isKindOfClass:[THEditImgCell class]] || sourceCollectionViewCell == nil, @"LxGridViewFlowLayout: Must use LxGridViewCell as your collectionViewCell class!");
            THEditImgCell *sourceGridViewCell = (THEditImgCell *)sourceCollectionViewCell;

            _beingMovedPromptView = [[UIView alloc] initWithFrame:CGRectOffset(sourceCollectionViewCell.frame, -10, -10)];

            sourceCollectionViewCell.highlighted = YES;
            UIView *highlightedSnapshotView = [sourceGridViewCell snapshotView];
            highlightedSnapshotView.frame = sourceGridViewCell.bounds;
            highlightedSnapshotView.alpha = 1;

            sourceCollectionViewCell.highlighted = NO;
            UIView *snapshotView = [sourceGridViewCell snapshotView];
            snapshotView.frame = sourceGridViewCell.bounds;
            snapshotView.alpha = 0;

            [_beingMovedPromptView addSubview:snapshotView];
            [_beingMovedPromptView addSubview:highlightedSnapshotView];
            [self.collectionView addSubview:_beingMovedPromptView];

            _sourceItemCollectionViewCellCenter = sourceCollectionViewCell.center;

            typeof(self) __weak weakSelf = self;
            [UIView animateWithDuration:0
                delay:0
                options:UIViewAnimationOptionBeginFromCurrentState
                animations:^{

                    typeof(self) __strong strongSelf = weakSelf;
                    if (strongSelf) {
                        highlightedSnapshotView.alpha = 0;
                        snapshotView.alpha = 1;
                    }
                }
                completion:^(BOOL finished) {

                    typeof(self) __strong strongSelf = weakSelf;
                    if (strongSelf) {
                        [highlightedSnapshotView removeFromSuperview];

                        if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didBeginDraggingItemAtIndexPath:)]) {
                            [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didBeginDraggingItemAtIndexPath:_movingItemIndexPath];
                        }
                    }
                }];
            [self invalidateLayout];
        } break;
        case UIGestureRecognizerStateChanged:
            break;
        case UIGestureRecognizerStateEnded:
        case UIGestureRecognizerStateCancelled: {
            [_displayLink invalidate];
            _displayLink = nil;

            NSIndexPath *movingItemIndexPath = _movingItemIndexPath;

            if (movingItemIndexPath) {
                if ([self.delegate respondsToSelector:@selector(collectionView:layout:willEndDraggingItemAtIndexPath:)]) {
                    [self.delegate collectionView:self.collectionView layout:self willEndDraggingItemAtIndexPath:movingItemIndexPath];
                }

                _movingItemIndexPath = nil;
                _sourceItemCollectionViewCellCenter = CGPointZero;

                UICollectionViewLayoutAttributes *movingItemCollectionViewLayoutAttributes = [self layoutAttributesForItemAtIndexPath:movingItemIndexPath];

                _longPressGestureRecognizer.enabled = NO;

                typeof(self) __weak weakSelf = self;
                [UIView animateWithDuration:0
                    delay:0
                    options:UIViewAnimationOptionBeginFromCurrentState
                    animations:^{
                        typeof(self) __strong strongSelf = weakSelf;
                        if (strongSelf) {
                            _beingMovedPromptView.center = movingItemCollectionViewLayoutAttributes.center;
                        }
                    }
                    completion:^(BOOL finished) {

                        _longPressGestureRecognizer.enabled = YES;

                        typeof(self) __strong strongSelf = weakSelf;
                        if (strongSelf) {
                            [_beingMovedPromptView removeFromSuperview];
                            _beingMovedPromptView = nil;
                            [strongSelf invalidateLayout];

                            if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didEndDraggingItemAtIndexPath:)]) {
                                [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didEndDraggingItemAtIndexPath:movingItemIndexPath];
                            }
                        }
                    }];
            }
        } break;
        case UIGestureRecognizerStateFailed:
            break;
        default:
            break;
    }
}

- (void)panGestureRecognizerTriggerd:(UIPanGestureRecognizer *)pan {
    switch (pan.state) {
        case UIGestureRecognizerStatePossible:
            break;
        case UIGestureRecognizerStateBegan:
        case UIGestureRecognizerStateChanged: {
            CGPoint panTranslation = [pan translationInView:self.collectionView];
            _beingMovedPromptView.center = CGPointOffset(_sourceItemCollectionViewCellCenter, panTranslation.x, panTranslation.y);

            NSIndexPath *sourceIndexPath = _movingItemIndexPath;
            NSIndexPath *destinationIndexPath = [self.collectionView indexPathForItemAtPoint:_beingMovedPromptView.center];

            if ((destinationIndexPath == nil) || [destinationIndexPath isEqual:sourceIndexPath]) {
                return;
            }
            if (sourceIndexPath == nil) {
                return;
            }

            if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] && [self.dataSource collectionView:self.collectionView itemAtIndexPath:sourceIndexPath canMoveToIndexPath:destinationIndexPath] == NO) {
                return;
            }

            if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) {
                [self.dataSource collectionView:self.collectionView itemAtIndexPath:sourceIndexPath willMoveToIndexPath:destinationIndexPath];
            }

            _movingItemIndexPath = destinationIndexPath;

            typeof(self) __weak weakSelf = self;
            [self.collectionView performBatchUpdates:^{
                typeof(self) __strong strongSelf = weakSelf;
                if (strongSelf) {
                    [strongSelf.collectionView deleteItemsAtIndexPaths:@[ sourceIndexPath ]];
                    [strongSelf.collectionView insertItemsAtIndexPaths:@[ destinationIndexPath ]];
                }
            }
                completion:^(BOOL finished) {
                    typeof(self) __strong strongSelf = weakSelf;
                    if ([strongSelf.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) {
                        [strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:sourceIndexPath didMoveToIndexPath:destinationIndexPath];
                    }
                }];
        } break;
        case UIGestureRecognizerStateEnded:
            break;
        case UIGestureRecognizerStateCancelled:
            break;
        case UIGestureRecognizerStateFailed:
            break;
        default:
            break;
    }
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if ([_panGestureRecognizer isEqual:gestureRecognizer]) {
        return _movingItemIndexPath != nil;
    }
    return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    //  only _longPressGestureRecognizer and _panGestureRecognizer can recognize simultaneously
    if ([_longPressGestureRecognizer isEqual:gestureRecognizer]) {
        return [_panGestureRecognizer isEqual:otherGestureRecognizer];
    }
    if ([_panGestureRecognizer isEqual:gestureRecognizer]) {
        return [_longPressGestureRecognizer isEqual:otherGestureRecognizer];
    }
    return NO;
}

#pragma mark - displayLink

- (void)displayLinkTriggered:(CADisplayLink *)displayLink {
    if (_remainSecondsToBeginEditing <= 0) {

        self.editing = YES;
        [_displayLink invalidate];
        _displayLink = nil;
    }

    _remainSecondsToBeginEditing = _remainSecondsToBeginEditing - 0.1;
}

#pragma mark - KVO and notification

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@stringify(collectionView)]) {
        if (self.collectionView) {
            [self addGestureRecognizers];
        } else {
            [self removeGestureRecognizers];
        }
    }
}

- (void)applicationWillResignActive:(NSNotification *)notificaiton {
    _panGestureRecognizer.enabled = NO;
    _panGestureRecognizer.enabled = YES;
}

@end
